package com.kevms.phonewars;

import java.util.LinkedList;
import java.util.Queue;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

/** 
* @class NetworkTask
* 
* @brief AsyncTask used to communicate over the network in
* another thread.
* 
* This AsyncTask allows the app to send and receive webservice
* requests in a thread running in the background.
*/ 
class NetworkTask extends AsyncTask<String, Integer, Void> {

	private static final String TAG = "NetworkTask";
	private final Combat combat;
	private Handler handler;
	private WebService mWebService;
	private Queue<String> msgQueue = new LinkedList<String>();
	
	boolean stop = false;
	
	public NetworkTask(Combat combat) {
		this.combat = combat;
		handler = new TaskHandler();
		mWebService = WebService.getInstance(combat);
	}
	
	public Handler getHandler() {
		return handler;
	}
	
	@Override
	protected Void doInBackground(String... str) {

		Looper.prepare();
		Looper.loop();
		return null;
	}
	
	@Override
	protected void onProgressUpdate(Integer... intarr) {
		String msg;
		switch(intarr[0]) {
		case 0:
			msg = msgQueue.poll();
			if(msg != null) {
				this.combat.showAlert(msg);
			}
			break;
		case 1:
			msg = msgQueue.poll();
			if(msg != null) {
				Toast.makeText( this.combat.getApplicationContext(), msg, Toast.LENGTH_SHORT ).show();
			}
			break;
		case 2:
			//this.combat.showAlert("working");
			this.combat.zoomToMyLocation();
			break;
		case 3:
			msg = msgQueue.poll();
			if(msg != null) {
				this.combat.gameOverAlert(msg);
			}
			break;
		case 4:
			this.combat.finish();
			break;
		}
		
	}

	@Override
	protected void onPostExecute(Void result) {
		
	}
	
	private final class TaskHandler extends Handler {
		public void handleMessage(Message msg) {
			JSONArray jArray = null;
			int type = (Integer)msg.obj;
			
			try {
				// Send message
				switch(type) {
					case UpdateType.UPDATE_POSITION:
						double[] c = combat.player.getPosition();
						Log.d(TAG, "c("+c[0]+","+c[1]+") trying to update position");
						try {
							jArray = mWebService.updatePosition(c[0], c[1]);
							publishProgress(2);
						} catch(Exception e) {
							publishProgress(4);
						}
						break;
					case UpdateType.UPDATE_GUN_SHOT:
						double[] dir = combat.player.getOrientation();
						Log.d(TAG, "dir("+dir[0]+","+dir[1]+") trying update gun shot");
						jArray = mWebService.updateGunShot(dir[0], dir[1]);
						break;
					case UpdateType.UPDATE_MINE_LAY:
						Log.d(TAG, "Trying to lay a mine");
						jArray = mWebService.updateMineLay();
						break;
					case UpdateType.UPDATE_MINE_DETONATE:
						Log.d(TAG, "Trying to detonate mines");
						jArray = mWebService.updateMineDetonate();
						combat.clearMineMarkers();
						msgQueue.add("Mines detonated.");
						publishProgress(1);
						break;
				}

				combat.updateStats();
				
				JSONObject jObject;
				for(int i = 0; i < jArray.length(); i++) {
					jObject = jArray.getJSONObject(i);
					switch(jObject.getInt("type")) {
						case UpdateType.UPDATE_MINE_LAY:
							updateMineLay(jObject);
							break;
						case UpdateType.UPDATE_KILLED_BY_MINE:
							updateKilledByMine(jObject);
							break;
						case UpdateType.UPDATE_PLAYER_JOINED:
							updatePlayerJoined(jObject);
							break;
						case UpdateType.UPDATE_KILLED_BY_GUN:
							updateKilledByGun(jObject);
							break;
						case UpdateType.UPDATE_LEAVE_MATCH:
							updateLeaveMatch(jObject);
							break;
						case UpdateType.UPDATE_GAME_OVER:
							updateGameOver(jObject);
							break;
					}
				}
			
			} catch (JSONException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		private void updateMineLay(JSONObject jObject) throws Exception {
			double[] loc = new double[2];
			loc[0] = jObject.getDouble("latitude");
			loc[1] = jObject.getDouble("longitude");
			combat.addMineMarker(loc);
			msgQueue.add("Planted mine.");
			publishProgress(0);
		}
		
		private void updateKilledByMine(JSONObject jObject) throws Exception {
			PWApplication appState = (PWApplication)combat.getApplicationContext();
			Player p1, p2;

			p1 = appState.findPlayer(jObject.getInt("player_id"));
			p1.addKills(1);

			p2 = appState.findPlayer(jObject.getInt("enemy_id"));
			p2.addDeaths(1);
			
			if(p1 == combat.player) {
				msgQueue.add("You exploded " + p2.getName());
				publishProgress(0);
			} else if(p2 == combat.player) {
				msgQueue.add(p1.getName() + " exploded you!");
				publishProgress(0);
			}
		}
		
		private void updateKilledByGun(JSONObject jObject) throws Exception {
			PWApplication appState = (PWApplication)combat.getApplicationContext();
			Player p1, p2;

			p1 = appState.findPlayer(jObject.getInt("player_id"));
			p1.addKills(1);
			
			p2 = appState.findPlayer(jObject.getInt("enemy_id"));
			p2.addDeaths(1);
			
			if(p1 == combat.player) {
				msgQueue.add("You shot " + p2.getName());
				publishProgress(0);
			} else if(p2 == combat.player) {
				msgQueue.add(p1.getName() + " shot you!");
				publishProgress(0);
			}
		}
		
		private void updatePlayerJoined(JSONObject jObject) throws Exception {
			PWApplication appState = (PWApplication)combat.getApplicationContext();
			Player p = new Player();
			
			p.setId(jObject.getInt("player_id"));
			p.setName(jObject.getString("name"));
			appState.addPlayer(p);
		}
		
		private void updateLeaveMatch(JSONObject jObject) throws Exception {
			PWApplication appState = (PWApplication)combat.getApplicationContext();
			
			Player p = appState.findPlayer(jObject.getInt("player_id"));
			appState.removePlayer(p);
		}
		
		private void updateGameOver(JSONObject jObject) throws Exception {
			PWApplication appState = (PWApplication)combat.getApplicationContext();
			Player p1;

			p1 = appState.findPlayer(jObject.getInt("player_id"));
			
			msgQueue.add(p1.getName() + " won the game!");
			publishProgress(3);
		}
	}
}